/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.ext.zul;

import cn.easyplatform.lang.Strings;
import cn.easyplatform.web.ext.Assignable;
import cn.easyplatform.web.ext.PairItem;
import cn.easyplatform.web.ext.ZkExt;
import org.zkoss.lang.Objects;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.Bandbox;

import java.util.ArrayList;
import java.util.List;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class BandboxExt extends Bandbox implements Assignable, ZkExt {

    public final static int DROPDOWN = 1;

    public final static int POPUP = 2;
    /**
     * 当groupQuery为空,表示列表，否则按指定的栏位值分组
     */
    public final static String DEFAULT = "default";
    /**
     * 具有上下关联的数据结构
     */
    public final static String GROUP = "group";
    /**
     * 具有上下关联的数据结构，且具有其它子结构
     */
    public final static String DUAL = "dual";

    /**
     * 显示类型:1，表示显示下拉框；2，表示弹出窗
     */
    private int _showType = 0;

    /**
     * 类型
     */
    private String _type = DEFAULT;

    /**
     * 值的分隔符
     */
    private String _separator;

    /**
     * 选择好的项
     */
    private List<PairItem> _items;

    /**
     * 查询语句，可以有多个栏位
     */
    private String _query;

    /**
     * 数据连接的资源id
     */
    private String _dbId;

    /**
     * 分组查询
     */
    private String _groupQuery;

    /**
     * 关联显示查询
     */
    private String _valueQuery;

    /**
     * 表示值的栏位
     */
    private String _valueField;

    /**
     * 值的类型
     */
    private String _valueType;

    /**
     * 标签栏位
     */
    private String _labelField;

    /**
     * 分组显示
     */
    private String _groupField;

    /**
     * 弹出窗口标题
     */
    private String _title;

    /**
     * 每一页的笔数
     */
    private int _pageSize;

    /**
     * 排序
     */
    private String _orderBy;

    /**
     * 显示行数
     */
    private boolean _showRowNumbers;

    /**
     * 过滤表达式
     */
    private String _filter;

    /**
     * 前台逐行脚本
     */
    private String _rowScript;

    /**
     * 分页组件是否显示详细信息
     */
    private boolean _pagingDetailed = true;

    /**
     * 分页组件显示模式
     */
    private String _pagingMold;

    /**
     * 分页组件显示style
     */
    private String _pagingStyle;

    /**
     * 列头可否调整大小
     */
    private boolean _sizable = true;

    /**
     * groupQuery不为空时是否延时加载分组数据
     */
    private boolean _lazy;

    /**
     * 当pageSize大于0，fetchAll为true，表示获取所有的数据，不需要分页，使用本身的分页
     */
    private boolean _fetchAll;

    /**
     * 初始逻辑，处理相关的映射
     */
    private String _mapping;

    /**
     * 是否填充右边空余空间
     */
    private boolean _span;

    /**
     * 行风格
     */
    private String _rowStyle;

    /**
     * 头部风格
     */
    private String _headStyle;

    /**
     * 冻结的列数，从左到右开始
     */
    private int _frozenColumns;

    /**
     * 初始打开的层次
     */
    private int _depth;

    /**
     * 冻结头部风格
     */
    private String _frozenStyle = "background: #dfded8";

    /**
     * 是否可多选
     */
    private boolean _multiple;
    /**
     * 显示的位置 center|nocenter|left|right|top|bottom|parent
     * 可以组合:"left,center"表示靠左中间
     */
    private String _position = "center";

    /**
     * 打开窗口的宽度
     */
    private String _panelWidth;

    /**
     * 打开窗口的高度
     */
    private String _panelHeight;

    /**
     * 自定义列头
     */
    private String _headers;
    /**
     * 双层时分层名称
     */
    private String _dualName;

    public String getDualName() {
        return _dualName;
    }

    public void setDualName(String dualName) {
        this._dualName = dualName;
    }
    private boolean _sizedByContent;

    public boolean isSizedByContent() {
        return _sizedByContent;
    }

    public void setSizedByContent(boolean sizedByContent) {
        this._sizedByContent = sizedByContent;
    }

    public String getHeaders() {
        return _headers;
    }

    public void setHeaders(String headers) {
        this._headers = headers;
    }

    public String getPanelWidth() {
        return _panelWidth;
    }

    public void setPanelWidth(String panelWidth) {
        this._panelWidth = panelWidth;
    }

    public String getPanelHeight() {
        return _panelHeight;
    }

    public void setPanelHeight(String panelHeight) {
        this._panelHeight = panelHeight;
    }

    public String getPosition() {
        return _position;
    }

    public void setPosition(String position) {
        this._position = position;
    }

    public String getValueQuery() {
        return _valueQuery;
    }

    public void setValueQuery(String valueQuery) {
        this._valueQuery = valueQuery;
    }

    public String getValueType() {
        return _valueType;
    }

    public void setValueType(String valueType) {
        this._valueType = valueType;
    }

    public boolean isMultiple() {
        return _multiple;
    }

    public void setMultiple(boolean multiple) {
        this._multiple = multiple;
    }

    public boolean isSpan() {
        return _span;
    }

    public void setSpan(boolean span) {
        this._span = span;
    }

    public String getRowStyle() {
        return _rowStyle;
    }

    public void setRowStyle(String rowStyle) {
        this._rowStyle = rowStyle;
    }

    public String getHeadStyle() {
        return _headStyle;
    }

    public void setHeadStyle(String headStyle) {
        this._headStyle = headStyle;
    }

    public int getFrozenColumns() {
        return _frozenColumns;
    }

    public void setFrozenColumns(int frozenColumns) {
        this._frozenColumns = frozenColumns;
    }

    public int getDepth() {
        return _depth;
    }

    public void setDepth(int depth) {
        this._depth = depth;
    }

    public String getFrozenStyle() {
        return _frozenStyle;
    }

    public void setFrozenStyle(String frozenStyle) {
        this._frozenStyle = frozenStyle;
    }

    public String getMapping() {
        return _mapping;
    }

    public void setMapping(String mapping) {
        this._mapping = mapping;
    }

    public String getQuery() {
        return _query;
    }

    public void setQuery(String query) {
        this._query = query;
    }

    public String getDbId() {
        return _dbId;
    }

    public void setDbId(String dbId) {
        this._dbId = dbId;
    }

    public String getGroupQuery() {
        return _groupQuery;
    }

    public void setGroupQuery(String groupQuery) {
        this._groupQuery = groupQuery;
    }

    public String getValueField() {
        return _valueField;
    }

    public void setValueField(String valueField) {
        this._valueField = valueField;
    }

    public String getLabelField() {
        return _labelField;
    }

    public void setLabelField(String labelField) {
        this._labelField = labelField;
    }

    public String getGroupField() {
        return _groupField;
    }

    public void setGroupField(String groupField) {
        this._groupField = groupField;
    }

    public String getTitle() {
        return _title;
    }

    public void setTitle(String title) {
        this._title = title;
    }

    public int getPageSize() {
        return _pageSize;
    }

    public void setPageSize(int pageSize) {
        this._pageSize = pageSize;
    }

    public String getOrderBy() {
        return _orderBy;
    }

    public void setOrderBy(String orderBy) {
        this._orderBy = orderBy;
    }

    public boolean isShowRowNumbers() {
        return _showRowNumbers;
    }

    public void setShowRowNumbers(boolean showRowNumbers) {
        this._showRowNumbers = showRowNumbers;
    }

    public String getFilter() {
        return _filter;
    }

    public void setFilter(String filter) {
        this._filter = filter;
    }

    public String getRowScript() {
        return _rowScript;
    }

    public void setRowScript(String rowScript) {
        this._rowScript = rowScript;
    }

    public boolean isPagingDetailed() {
        return _pagingDetailed;
    }

    public void setPagingDetailed(boolean pagingDetailed) {
        this._pagingDetailed = pagingDetailed;
    }

    public String getPagingMold() {
        return _pagingMold;
    }

    public void setPagingMold(String pagingMold) {
        this._pagingMold = pagingMold;
    }

    public String getPagingStyle() {
        return _pagingStyle;
    }

    public void setPagingStyle(String pagingStyle) {
        this._pagingStyle = pagingStyle;
    }

    public boolean isSizable() {
        return _sizable;
    }

    public void setSizable(boolean sizable) {
        this._sizable = sizable;
    }

    public boolean isLazy() {
        return _lazy;
    }

    public void setLazy(boolean lazy) {
        this._lazy = lazy;
    }

    public boolean isFetchAll() {
        return _fetchAll;
    }

    public void setFetchAll(boolean fetchAll) {
        this._fetchAll = fetchAll;
    }

    public void setItems(List<PairItem> items) {
        this._items = items;
        StringBuilder sb = new StringBuilder();
        if (items != null && !items.isEmpty()) {
            for (PairItem item : items)
                sb.append(item.getLabel()).append(_separator == null ? "," : _separator);
            sb.deleteCharAt(sb.length() - 1);
        }
        this._value = sb.toString();
        smartUpdate("value", this._value);
    }

    public void setItem(Object id, String label) {
        if (this._items != null)
            this._items.clear();
        else this._items = new ArrayList<>();
        this._items.add(new PairItem(id, label));
        this._value = label;
        smartUpdate("value", this._value);
    }

    @Override
    public String getValue() {
        if (_showType > 0) {
            if (this._items == null || this._items.isEmpty())
                return "";
            StringBuilder sb = new StringBuilder();
            for (PairItem item : _items)
                sb.append(item.getValue()).append(_separator == null ? "," : _separator);
            sb.deleteCharAt(sb.length() - 1);
            return sb.toString();
        } else
            return super.getValue();
    }

    public String getLabel() {
        if (this._items == null || this._items.isEmpty())
            return "";
        StringBuilder sb = new StringBuilder();
        for (PairItem item : _items)
            sb.append(item.getLabel()).append(_separator == null ? "," : _separator);
        sb.deleteCharAt(sb.length() - 1);
        return sb.toString();
    }

    @Override
    public void setValue(Object value) {
        if (_showType > 0) {
            Assignable ext = (Assignable) getAttribute("$proxy");
            if (ext != null)
                ext.setValue(value);
        } else
            super.setValue((String) value);
    }

    public List<PairItem> getItems() {
        return this._items;
    }

    public boolean exists(Object value) {
        if (this._items != null) {
            for (PairItem item : this._items) {
                if (Objects.equals(value, item.getValue()))
                    return true;
            }
        }
        return false;
    }

    public int getShowType() {
        return _showType;
    }

    public void setShowType(int showType) {
        this._showType = showType;
    }

    public String getSeparator() {
        return _separator;
    }

    public void setSeparator(String separator) {
        if (!Objects.equals(_separator, separator)) {
            this._separator = separator;
            smartUpdate("separator", _separator);
        }
    }

    public String getMold() {
        if (_showType == 0)
            return super.getMold();
        return _showType == 1 ? "dd" : "pp";
    }

    protected void renderProperties(org.zkoss.zk.ui.sys.ContentRenderer renderer)
            throws java.io.IOException {
        super.renderProperties(renderer);
        if (!Strings.isBlank(_separator))
            render(renderer, "separator", _separator);
    }

    public void service(org.zkoss.zk.au.AuRequest request, boolean everError) {
        final String cmd = request.getCommand();
        if (cmd.equals(Events.ON_CHANGE)) {
            if (this._showType > 0) {
                int idx = (Integer) request.getData().get("value");
                if (_items != null) {
                    _items.remove(idx);
                    Events.postEvent(new Event(cmd, this, idx));
                } else if (this._value != null) {
                    StringBuilder sb = new StringBuilder();
                    String sep = _separator == null ? "," : _separator;
                    String[] strs = _value.toString().split(sep);
                    for (int i = 0; i < strs.length; i++) {
                        if (i != idx) {
                            sb.append(strs[i]);
                            sb.append(sep);
                        }
                    }
                    if (sb.length() > 0)
                        sb.deleteCharAt(sb.length() - 1);
                    this._value = sb.toString();
                    Events.postEvent(new Event(cmd, this, this._value));
                }
            } else
                super.service(request, everError);
        } else
            super.service(request, everError);
    }

    @Override
    public void setType(String type) {
        this._type = type;
    }

    @Override
    public String getType() {
        return _type;
    }
}
